﻿using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using nyxwin.Data.Base;
using nyxwin.Data.Utils;
using nyxwin.Data.Cache;
using nyxwin.Data.Common;

namespace nyxwin.Data.Mail
{
    public class MailManager : RemoteBase
    {
        #region Events

        public event EventHandler<GetMailsEventArgs> GetMailsCompleted;
        public event EventHandler<SendMailEventArgs> SendMailCompleted;
        public event EventHandler<DeleteMailEventArgs> DeleteMailCompleted;
        public event EventHandler<RememberMailEventArgs> RememberMailCompleted;

        #endregion

        #region Construction

        public MailManager(string authorizationNick, string authorizationToken)
            : base(authorizationNick, authorizationToken)
        {
            base.InvocationCompleted += MailManagerInvocationCompleted;
        }

        #endregion

        #region GetMails
        
        public List<Mail> /* result is from cache */ GetMails(MailQuery query)
        {
            if (null == query)
                throw new ArgumentNullException("mail query");

            var parameters = new Dictionary<string, string>();

            if (query.IsFilterUser)
                parameters.Add("filter_user", query.FilterUser);

            if (query.IsFilterContents)
                parameters.Add("filter_text", query.FilterContents);

            if (!query.LastId.HasValue && !query.FirstId.HasValue)
                parameters.Add("direction", "newest");

            if (query.LastId.HasValue && !query.FirstId.HasValue)
            {
                parameters.Add("direction", "older");
                parameters.Add("id_mail", Convert.ToString(query.LastId.Value));
            }
            else if (!query.LastId.HasValue && query.FirstId.HasValue)
            {
                parameters.Add("direction", "newer");
                parameters.Add("id_mail", Convert.ToString(query.FirstId.Value));
            }

            base.InvokeRemote("mail", "messages", parameters.ToUrlArray(), query == MailQuery.Default);

            var result = CacheProvider.Instance.Retrieve<List<Mail>>(CacheType.MailCache);

            if (result != null)
            {
                foreach (var item in result)
                {
                    item.Active = null;
                }
            }

            return result;
        }

        #endregion

        #region SendMail

        public void SendMail(string recipient, string message)
        {
            if (string.IsNullOrEmpty(recipient) || string.IsNullOrEmpty(message))
                throw new ArgumentNullException("recipient/message is null or empty");

            var parameters = new Dictionary<string, string>();

            parameters.Add("recipient", recipient);
            parameters.Add("message", message);

            base.InvokeRemote("mail", "send", parameters.ToUrlArray());
        }

        #endregion

        #region DeleteMail

        public void DeleteMail(int mailId)
        {
            var parameters = new Dictionary<string, string>();

            parameters.Add("id_mail", Convert.ToString(mailId));

            base.InvokeRemote("mail", "delete", parameters.ToUrlArray());
        }

        #endregion

        #region AddToReminder

        public void AddToReminder(int mailId)
        {
            var parameters = new Dictionary<string, string>();

            parameters.Add("id_mail", Convert.ToString(mailId));
            parameters.Add("reminder", "1");

            base.InvokeRemote("mail", "reminder", parameters.ToUrlArray());
        }

        #endregion

        #region FireGetMailsCompleted

        private void FireGetMailsCompleted(GetMailsEventArgs e)
        {
            if (null != GetMailsCompleted)
            {
                GetMailsCompleted(this, e);
            }
        }

        #endregion

        #region FireSendMailCompleted

        private void FireSendMailCompleted(SendMailEventArgs e)
        {
            if (null != SendMailCompleted)
            {
                SendMailCompleted(this, e);
            }
        }

        #endregion

        #region FireDeleteMailCompleted

        private void FireDeleteMailCompleted(DeleteMailEventArgs e)
        {
            if (null != DeleteMailCompleted)
            {
                DeleteMailCompleted(this, e);
            }
        }

        #endregion

        #region FireRememberMailCompleted

        private void FireRememberMailCompleted(RememberMailEventArgs e)
        {
            if (null != RememberMailCompleted)
            {
                RememberMailCompleted(this, e);
            }
        }

        #endregion

        #region MailManagerInvocationCompleted

        private void MailManagerInvocationCompleted(object sender, InvocationEventArgs e)
        {
            if (e.Method != "mail")
                throw new NyxException(string.Format("Expected 'mail', but got '{0}' instead", e.Method));

            try
            {
                var data = JsonConvert.DeserializeObject(e.Result) as JObject;

                switch (e.Parameter)
                {
                    case "messages":
                        {
                            var listMails = new List<Mail>();
                            var dStart = DateTime.Now;

                            foreach (JObject row in data["data"])
                            {
                                var m = new Mail();
                                m.Id = row.Value<int>("id_mail");
                                m.Nick = row.Value<string>("other_nick");
                                m.Direction = row.Value<string>("direction");
                                m.Time = row.Value<long>("time");

                                if (row["active"] != null)
                                    m.Active = Active.ParseJson(row.Value<JObject>("active"), dStart);
                                else
                                    m.Active = null;

                                m.Content = row.Value<string>("content");

                                bool unread = false;
                                if (row["new"] != null)
                                    unread = row.Value<string>("new").Equals("yes");
                                m.Unread = unread;

                                bool unreadOther = false;
                                if (row["message_status"] != null)
                                    unreadOther = row.Value<string>("message_status").Equals("unread");
                                m.UnreadOther = unreadOther;

                                listMails.Add(m);
                            }

                            if (e.State is bool && (bool)e.State)
                            {
                                CacheProvider.Instance.Flush(listMails, CacheType.MailCache);
                            }

                            FireGetMailsCompleted(new GetMailsEventArgs { MailList = listMails });
                        }
                        break;

                    /* TODO: check for 'ok' in api result */
                    case "send":
                        {
                            FireSendMailCompleted(new SendMailEventArgs { Result = true });
                        }
                        break;

                    case "delete":
                        {
                            FireDeleteMailCompleted(new DeleteMailEventArgs { Result = true });
                        }
                        break;

                    case "reminder":
                        {
                            FireRememberMailCompleted(new RememberMailEventArgs { Result = true });
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                FireErrorOccurred(new ErrorOccurredEventArgs(ex) { Error = true, ErrorMessage = ex.ToString() });
            }
        }

        #endregion
    }
}